/*
日志中间件
记录服务端相关记录
*/

package middleware

import (
    "fmt"
    "os"
    "time"

    "github.com/gin-gonic/gin"
    retalog "github.com/lestrrat-go/file-rotatelogs"
    "github.com/rifflock/lfshook"
    "github.com/sirupsen/logrus"
)

// Logger 日志中间件
// todo 可考虑更换其他日志中间件
func Logger() gin.HandlerFunc {
    filePath := "log/log"
    //linkName := "latest_log.log"

    scr, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
    if err != nil {
        fmt.Println("err:", err)
    }
    logger := logrus.New()

    logger.Out = scr

    logger.SetLevel(logrus.DebugLevel)

    logWriter, _ := retalog.New(
        filePath+"%Y%m%d.log",
        retalog.WithMaxAge(7*24*time.Hour),
        retalog.WithRotationTime(24*time.Hour),
        //retalog.WithLinkName(linkName),
    )

    writeMap := lfshook.WriterMap{
        logrus.InfoLevel:  logWriter,
        logrus.FatalLevel: logWriter,
        logrus.DebugLevel: logWriter,
        logrus.WarnLevel:  logWriter,
        logrus.ErrorLevel: logWriter,
        logrus.PanicLevel: logWriter,
    }
    Hook := lfshook.NewHook(writeMap, &logrus.TextFormatter{
        TimestampFormat: "2006-01-02 15:04:05",
    })

    logger.AddHook(Hook)

    return func(c *gin.Context) {
        startTime := time.Now()
        c.Next()
        stopTime := time.Since(startTime).Milliseconds()
        spendTime := fmt.Sprintf("%d ms", stopTime)
        hostName, err := os.Hostname()
        if err != nil {
            hostName = "unknown"
        }
        statusCode := c.Writer.Status()
        clientIp := c.ClientIP()
        userAgent := c.Request.UserAgent()
        dataSize := c.Writer.Size()
        if dataSize < 0 {
            dataSize = 0
        }
        method := c.Request.Method
        path := c.Request.RequestURI

        entry := logger.WithFields(logrus.Fields{
            "HostName":  hostName,
            "status":    statusCode,
            "SpendTime": spendTime,
            "Ip":        clientIp,
            "Method":    method,
            "Path":      path,
            "DataSize":  dataSize,
            "Agent":     userAgent,
        })
        if len(c.Errors) > 0 {
            entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String())
        }
        if statusCode >= 500 {
            entry.Error()
        } else if statusCode >= 400 {
            entry.Warn()
        } else {
            entry.Info()
        }
    }
}
